/** * Copyright 2014 Lockheed Martin Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package streamflow.server.resource; import com.google.inject.Inject; import com.sun.jersey.core.header.FormDataContentDisposition; import com.sun.jersey.multipart.FormDataParam; import java.io.ByteArrayInputStream; import java.io.IOException; import java.util.Collection; import java.util.Date; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import streamflow.model.FileInfo; import streamflow.service.FileService; import streamflow.service.util.IDUtils; import org.apache.commons.codec.digest.DigestUtils; import org.apache.tika.detect.DefaultDetector; import org.apache.tika.detect.Detector; import org.apache.tika.metadata.Metadata; import org.apache.tika.mime.MimeTypes; @Path("/files") public class FileResource { private final FileService fileService; private static final Detector detector = new DefaultDetector( MimeTypes.getDefaultMimeTypes()); @Inject public FileResource(FileService fileService) { this.fileService = fileService; } @GET @Produces(MediaType.APPLICATION_JSON) public Collection<FileInfo> listFiles() { return fileService.listFiles(); } @POST @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.APPLICATION_JSON) public FileInfo createFile(@FormDataParam("file") byte[] fileContent, @FormDataParam("file") FormDataContentDisposition fileDetail, @HeaderParam("Content-type") String contentType) { // Validate the input parameters if (fileContent == null) { throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) .entity("File content was specified in the request").build()); } // Save the upload metadata for later retrieval FileInfo fileInfo = new FileInfo(); fileInfo.setId(IDUtils.randomUUID()); fileInfo.setFileName(fileDetail.getFileName()); fileInfo.setFileSize(fileContent.length); fileInfo.setCreated(new Date()); fileInfo.setModified(fileInfo.getCreated()); fileInfo.setContentHash(DigestUtils.md5Hex(fileContent)); try { // Reliably detect the mime type using Tika fileInfo.setFileType(detector.detect( new ByteArrayInputStream(fileContent), new Metadata()).toString()); } catch (IOException ex) { // Use a default type of binary just in case fileInfo.setFileType("application/octet-stream"); } // Persist the upload metadata after the file is successfully written fileInfo = fileService.saveFile(fileInfo, fileContent); return fileInfo; } @GET @Path("/{fileId}") @Produces(MediaType.APPLICATION_JSON) public FileInfo getFile(@PathParam("fileId") String fileId) { return fileService.getFileInfo(fileId); } @PUT @Path("/{fileId}") @Consumes(MediaType.APPLICATION_JSON) public Response updateFile(@PathParam("fileId") String fileId, FileInfo fileInfo) { fileService.updateFile(fileId, fileInfo); return Response.ok().build(); } @DELETE @Path("/{fileId}") public Response deleteFile(@PathParam("fileId") String fileId) { fileService.deleteFile(fileId); return Response.ok().build(); } @GET @Path("/{fileId}/content") public Response getFileContent(@PathParam("fileId") String fileId) { byte[] fileContent = fileService.getFileContent(fileId); // Retrieve the file metadata to build the request FileInfo fileInfo = fileService.getFileInfo(fileId); return Response.ok().entity(fileContent).type(fileInfo.getFileType()) .header("Content-Disposition", "attachment; filename=" + fileInfo.getFileName()) .header("Cache-Control", "no-cache").build(); } @POST @Path("/{fileId}/content") @Consumes(MediaType.MULTIPART_FORM_DATA) @Produces(MediaType.APPLICATION_JSON) public FileInfo updateFileContent(@PathParam("fileId") String fileId, @FormDataParam("file") byte[] fileContent, @FormDataParam("file") FormDataContentDisposition fileDetail, @HeaderParam("Content-type") String contentType) { // Validate the input parameters if (fileContent == null) { throw new WebApplicationException(Response.status(Response.Status.BAD_REQUEST) .entity("File data was not provided in the request").build()); } FileInfo fileInfo = fileService.getFileInfo(fileId); fileInfo.setFileName(fileDetail.getFileName()); fileInfo.setFileSize((long) fileContent.length); fileInfo.setModified(new Date()); fileInfo.setContentHash(DigestUtils.md5Hex(fileContent)); try { // Reliably detect the mime type using Tika fileInfo.setFileType(detector.detect( new ByteArrayInputStream(fileContent), new Metadata()).toString()); } catch (IOException ex) { // Use a default type of binary just in case fileInfo.setFileType("application/octet-stream"); } // Persist the upload metadata after the file is successfully written fileService.updateFile(fileId, fileInfo, fileContent); return fileInfo; } }